/**
 * Copyright (c) 2020 - present, Inspur Genersoft Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
import { DataGridProps, dataGridProps } from './data-grid.props';
import { computed, defineComponent, onUnmounted, onMounted, ref, nextTick, watch, SetupContext } from 'vue';
import { useResizeObserver } from '@vueuse/core';
import { useVisualData } from './composition/use-visual-data';
import { useCellPosition } from './composition/use-positon-style';
import { useVirtualScroll } from './composition/use-virtual-scroll';
import { useRow } from './composition/use-row';
import { useColumn } from './composition/use-column';
import { useFitColumn } from './composition/use-fit-column';
import { useSidebar } from './composition/use-sidebar';
import { useGroupData } from './composition/use-group-data';
import { useDataView } from './composition/use-data-view';
import { useEdit } from './composition/use-edit';
import { useColumnFilter } from './composition/use-column-filter';
import { useFilterHistory } from './composition/use-filter-history';
import { useSort } from './composition/use-sort';

import getDataArea from './components/data/data-area.component';
import getDataGridHeader from './components/header/data-grid-header.component';
import getDataGridPagination from './components/pagination/data-grid-pagination.component';
import getDataGridSidebar from './components/sidebar/data-grid-sidebar.component';
import getDataGridSummary from './components/summary/data-grid-summary.component';
import getFilterPanel from './components/filter-panel/filter-panel.component';
import getGroupPanel from './components/group-panel/group-panel.component';
import getHorizontalScrollbar from './components/scrollbar/horizontal-scrollbar.component';
import getVerticalScrollbar from './components/scrollbar/vertical-scrollbar.component';
import './data-grid.css';
import { useSelection } from './composition/use-selection';
import { useCommandColumn } from './composition/use-command-column';
import { VisualData } from './composition/types';
import { useVisualDataBound } from './composition/use-visual-data-bound';
import { useVisualDataCell } from './composition/use-visual-data-cell';
import { useVisualDataRow } from './composition/use-visual-data-row';
import { useVisualGroupRow } from './composition/use-visual-group-row';
import { useVisualSummaryRow } from './composition/use-visual-summary-row';
import { useDragColumn } from './composition/use-drag-column';
import { useGroupColumn } from './composition/use-group-column';
import { useFilter } from './composition/use-filter';

export default defineComponent({
    name: 'FDataGrid',
    props: dataGridProps,
    emits: [],
    setup(props: DataGridProps, context: SetupContext) {
        const columns = ref(props.columns);
        const defaultVisibleCapacity = 20;
        const preloadCount = 0;
        const dataGridRef = ref<any>();
        const gridContentRef = ref<any>();
        const primaryGridContentRef = ref<any>();
        const leftFixedGridContentRef = ref<any>();
        const rightFixedGridContentRef = ref<any>();
        const showStripe = ref(props.showStripe);
        const mouseInContent = ref(false);
        const wrapContent = ref(props.rowOption?.wrapContent || false);
        const useSelectionComposition = useSelection(props);
        const useGroupDataComposition = useGroupData(props);
        const useColumnComposition = useColumn(props);
        const useFilterComposition = useFilter();
        const dataView = useDataView(props, useColumnComposition, useFilterComposition, useGroupDataComposition, useSelectionComposition);
        const visibleCapacity = computed(() => {
            return dataView.totalItems.value < defaultVisibleCapacity ? dataView.totalItems.value : defaultVisibleCapacity;
        });

        const useCommandColumnComposition = useCommandColumn(props);
        const { applyCommands } = useCommandColumnComposition;

        applyCommands(columns);

        const useSortComposition = useSort(props);
        const { applyColumnSorter, columnContext } = useColumnComposition;
        applyColumnSorter(dataView, useSortComposition);

        const useGroupColumnComposition = useGroupColumn(props, columnContext);

        const useFitColumnComposition = useFitColumn(props, columnContext, useGroupColumnComposition);
        const { calculateColumnsSize } = useFitColumnComposition;

        const useEditComposition = useEdit(props);

        const useVisualDataBoundComposition = useVisualDataBound();

        const useVisualDataCellComposition = useVisualDataCell(props, useEditComposition, useVisualDataBoundComposition);

        const useVisualDataRowComposition = useVisualDataRow(
            props,
            useEditComposition,
            useVisualDataBoundComposition,
            useVisualDataCellComposition
        );

        const useVisualGroupRowComposition = useVisualGroupRow(props, useVisualDataCellComposition, useVisualDataRowComposition);

        const useVisualSummaryRowComposition = useVisualSummaryRow(props, useVisualDataCellComposition, useVisualDataRowComposition);

        const useVisualDataComposition = useVisualData(
            props,
            columns,
            dataView,
            visibleCapacity,
            preloadCount,
            useVisualDataRowComposition,
            useVisualGroupRowComposition,
            useVisualSummaryRowComposition
        );
        const { getVisualData } = useVisualDataComposition;

        const useCellPositionComposition = useCellPosition(props, columnContext);

        const useSidebarComposition = useSidebar(props);
        const { sidebarWidth } = useSidebarComposition;

        const visibleDatas = ref(getVisualData(0, visibleCapacity.value + preloadCount - 1));

        const useVirtualScrollComposition = useVirtualScroll(
            props,
            dataView,
            visibleDatas,
            columnContext,
            useVisualDataComposition,
            visibleCapacity,
            preloadCount,
            sidebarWidth
        );
        const { onWheel, dataGridWidth, viewPortHeight, viewPortWidth, resetScroll } = useVirtualScrollComposition;

        const useFilterHistoryComposition = useFilterHistory();

        const useColumnFilterComposition = useColumnFilter(
            gridContentRef,
            rightFixedGridContentRef,
            dataView,
            useFilterHistoryComposition,
            useVirtualScrollComposition
        );

        const useRowComposition = useRow(props, useSelectionComposition, visibleDatas);

        const useDragColumnComposition = useDragColumn(
            props,
            context,
            useColumnComposition,
            dataView,
            useGroupColumnComposition,
            useGroupDataComposition,
            useVirtualScrollComposition
        );

        const gridClass = computed(() => {
            const classObject = {
                'fv-grid': true,
                'fv-datagrid-strip': showStripe.value
            } as Record<string, boolean>;
            return classObject;
        });

        const gridContentClass = computed(() => {
            const classObject = {
                'fv-grid-content': true,
                'fv-grid-content-hover': mouseInContent.value,
                'fv-grid-wrap-content': wrapContent.value
            } as Record<string, boolean>;
            return classObject;
        });

        const { renderDataArea } = getDataArea(
            props,
            primaryGridContentRef,
            leftFixedGridContentRef,
            rightFixedGridContentRef,
            useCellPositionComposition,
            useColumnComposition,
            useEditComposition,
            useGroupDataComposition,
            useRowComposition,
            useVisualDataComposition,
            useVirtualScrollComposition,
            visibleDatas
        );

        const { renderGridHeader, renderGridColumnResizeOverlay } = getDataGridHeader(
            props,
            gridContentRef,
            leftFixedGridContentRef,
            rightFixedGridContentRef,
            useColumnComposition,
            dataView,
            useDragColumnComposition,
            useColumnFilterComposition,
            useFilterComposition,
            useFilterHistoryComposition,
            useFitColumnComposition,
            useGroupColumnComposition,
            useSidebarComposition,
            useSortComposition,
            useVirtualScrollComposition,
            viewPortWidth
        );

        const { renderDataGridPagination } = getDataGridPagination(props, dataView, useVirtualScrollComposition);

        const { renderDataGridSidebar } = getDataGridSidebar(props, useRowComposition, useSidebarComposition, useVirtualScrollComposition);

        const { renderDataGridSummery } = getDataGridSummary(props, dataView, useColumnComposition);

        const { renderHorizontalScrollbar } = getHorizontalScrollbar(props, gridContentRef, useVirtualScrollComposition);

        const { renderVerticalScrollbar } = getVerticalScrollbar(props, gridContentRef, useVirtualScrollComposition);

        const { renderFilterPanel } = getFilterPanel(
            props,
            useColumnComposition,
            dataView,
            useFilterComposition,
            useVirtualScrollComposition
        );

        const { renderGroupPanel } = getGroupPanel(
            props,
            dataView,
            useDragColumnComposition,
            useGroupDataComposition,
            useVirtualScrollComposition
        );

        function updateGridViewPortWidth($event: UIEvent) {
            viewPortHeight.value = primaryGridContentRef.value?.clientHeight || 0;
            dataGridWidth.value = gridContentRef.value?.clientWidth || 0;
            calculateColumnsSize(columnContext, gridContentRef.value, viewPortWidth);
        }

        function onGridContentResize() {
            viewPortHeight.value = primaryGridContentRef.value?.clientHeight || 0;
            dataGridWidth.value = gridContentRef.value?.clientWidth || 0;
            calculateColumnsSize(columnContext, gridContentRef.value, viewPortWidth);
        }

        onMounted(() => {
            if (gridContentRef.value) {
                useResizeObserver(gridContentRef.value, onGridContentResize);
                // window.addEventListener('resize', updateGridViewPortWidth);
                calculateColumnsSize(columnContext, gridContentRef.value, viewPortWidth);
                visibleDatas;
                nextTick(() => {
                    if (gridContentRef.value) {
                        dataGridWidth.value = gridContentRef.value.clientWidth;
                    }
                    if (primaryGridContentRef.value) {
                        viewPortWidth.value = primaryGridContentRef.value.clientWidth;
                        viewPortHeight.value = primaryGridContentRef.value.clientHeight;
                    }
                });
            }
        });

        onUnmounted(() => {
            // window.removeEventListener('resize', updateGridViewPortWidth);
        });

        watch(viewPortWidth, () => {
            if (gridContentRef.value) {
                calculateColumnsSize(columnContext, gridContentRef.value, viewPortWidth);
            }
        });

        function addNewDataItem() {
            dataView.insertNewDataItem();
            resetScroll();
        }

        function editDataItem(visualDataRow: VisualData) {
            useEditComposition.onEditingRow(visualDataRow);
        }

        function removeDataItem(dataIndex: number) {
            dataView.removeDataItem(dataIndex);
            resetScroll();
        }

        function acceptDataItem(visualDataRow: VisualData) {
            useEditComposition.acceptEditingRow(visualDataRow);
        }

        function cancelDataItem(visualDataRow: VisualData) {
            useEditComposition.cancelEditingRow(visualDataRow);
        }

        context.expose({ addNewDataItem, removeDataItem, editDataItem, acceptDataItem, cancelDataItem });

        return () => {
            return (
                <div ref={dataGridRef} class={gridClass.value} style="height:600px" onWheel={onWheel}>
                    {renderFilterPanel()}
                    {renderGroupPanel()}
                    {renderGridHeader()}
                    <div
                        ref={gridContentRef}
                        class={gridContentClass.value}
                        onMouseover={() => {
                            mouseInContent.value = true;
                        }}
                        onMouseleave={() => {
                            mouseInContent.value = false;
                        }}>
                        {renderDataGridSidebar(visibleDatas)}
                        {renderDataArea()}
                        {renderHorizontalScrollbar()}
                        {renderVerticalScrollbar()}
                    </div>
                    {renderDataGridSummery()}
                    {renderDataGridPagination()}
                    {renderGridColumnResizeOverlay()}
                </div>
            );
        };
    }
});
